//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    Crolengi, this program (a part of program) is gameengine based on C++\Directx
//    Copyright (C) 2008 Pashinin Anton Alekseevich (Crol)
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//    (INCLUDING NEGLIGENCE OR OTHERWISE) 
//    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//    EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//    Contacts: 
//    Mail: crolengi@gmail.com
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


#include "..\\StdAfx.h"
#include "character.h"

//#include "physObject.h"
#include "..//physx//cooking.h"
#include "..//physx//nxUtilities.h"
#include "..//physx//Stream.h"
#include "..//physx//SamplesVRDSettings.h"
#include "..//physx//NxCapsuleController.h"
#include "..//physx//NxControllerManager.h"
#include "..//physx//NxPhysics.h"

#include "..//physx//cooking.h"
#include "..//physx/nxUtilities.h"
#include "..//physx//Stream.h"
//#include "physx//NxControllerManager.h"
#include "charController.h"

void character::update(float dt)
{
	if(!con) return;
	//	NxF32 sharpness = 0.1f;

		NxF32 sharpness = 11.001f;
		NxU32 collisionFlags;
		
		NxVec3 d;
		d.x=vec[0];
		d.y=vec[1];
		d.z=vec[2];
		d= d*dt;

//		if(heightDelta!=0.0f)
//			d.y+=heightDelta;
		con->move(d, -1, 0.000001f, collisionFlags, sharpness);
		//return collisionFlags;

		if (collisionFlags & NXCC_COLLISION_SIDES)  {
		vec[0]=0;vec[2]=0;
		}
}

void character::SetPosition(float x, float y, float z)
{
	NxExtendedVec3 v;
	v.x=x; v.y=y; v.z=z;

	if(con)
		con->setPosition(v);
}

void character::GetPosition(float* vec3)
{
	if(!con) return;

	NxExtendedVec3 v=con->getPosition();
	vec3[0]=v.x;
	vec3[1]=v.y;
	vec3[2]=v.z;
}

void character::GetPosition(NxExtendedVec3* vec3)
{
	if(!con) return;

	*vec3=con->getPosition();
    
}

void character::GetVector(float* vec3)
{
	memcpy(vec3, vec, sizeof(float)*3);
}

void character::SetVector(float* vec3)
{
//	vec3[2]=-vec3[2];
	memcpy(vec, vec3, sizeof(float)*3);
}
void character::SetVector(NxVec3 vector)
{
  
  vec[0]=vector.x;vec[1]=vector.y;vec[2]=vector.z;
}

void character::AddVector(NxVec3 vector)
{
  
  vec[0]+=vector.x;vec[1]+=vector.y;vec[2]+=vector.z;
}

bool character::createCapsule(float r, float h)
{
	NxCapsuleControllerDesc desc;
	desc.position.x		= 0;
	desc.position.y		= 0;
	desc.position.z		= 0;
	desc.radius			= r;//gInitialRadius * scale;
	desc.height			= h;//gInitialHeight * scale;
	desc.upDirection	= NX_Y;
			
	//		desc.slopeLimit		= cosf(NxMath::degToRad(45.0f));
	desc.slopeLimit		= 0;
	desc.skinWidth		= 0.015f; //SKINWIDTH;
	desc.stepOffset		= 0.5f;
//	desc.stepOffset		= 0.5f; //gInitialRadius * 0.5 * scale;
	//	desc.stepOffset	= 0.01f;
	//		desc.stepOffset		= 0;	// Fixes some issues
	//		desc.stepOffset		= 10;
	desc.callback		= &gControllerHitReport;

	//desc.flags	|= NX_AF_DISABLE_COLLISION

	con=CCMgr->createController(g_pScene, desc);
	if(!con) MessageBox(NULL, "character controller (character::CreateCapsule) not created!", "afx", 0);

	return true;
}


////////////////////////////// controller

NxControllerAction  ControllerHitReport::onShapeHit(const NxControllerShapeHit& hit)
{
		//		renderTerrainTriangle(hit.faceID);*/

		
		if(1 && hit.shape)
		{
			NxCollisionGroup group = hit.shape->getGroup();
			if(group!=GROUP_COLLIDABLE_NON_PUSHABLE)
			{
				NxActor& actor = hit.shape->getActor();
				if(actor.isDynamic())
				{
					/*
					if ((gPts[gNbPts].x != hit.worldPos.x) || (gPts[gNbPts].y != hit.worldPos.y) || (gPts[gNbPts].z != hit.worldPos.z))
					{
						gPts[gNbPts++].x = hit.worldPos.x;
						gPts[gNbPts++].y = hit.worldPos.y;
						gPts[gNbPts++].z = hit.worldPos.z;
						if (gNbPts==MAX_NB_PTS)  gNbPts = 0;
					}
					*/

					// We only allow horizontal pushes. Vertical pushes when we stand on dynamic objects creates
					// useless stress on the solver. It would be possible to enable/disable vertical pushes on
					// particular objects, if the gameplay requires it.
					if(hit.dir.y>=0.0f)
					{
						//NxVec3 vec;
						//vec.zero();
						//vec.y = -9;

						//NxF32 coeff = 0.6f*hit.length*actor.getMass();// 
						//if (actor.isSleeping())
					//	actor.setAngularVelocity(NxVec3(0,0,0));
			           // actor.setLinearVelocity(NxVec3(0,0,0));
			           // actor.setMaxAngularVelocity(10);
					   // actor.addForceAtLocalPos(hit.dir*coeff, NxVec3(0,0,0), NX_IMPULSE);
						///hit.controller->setCollision(true);
                       // return NX_ACTION_NONE;

						//NxActor *act = hit.controller->getActor(); 
                        //act->raiseBodyFlag(NX_BF_KINEMATIC); 
                        //act->setMass(50.0f);
						//act->addForceAtPos(-hit.dir*coeff, NxVec3(hit.worldPos.x,hit.worldPos.y,hit.worldPos.z), NX_IMPULSE);

					   //actor.addForceAtPos(hit.dir*coeff, NxVec3(hit.worldPos.x,hit.worldPos.y,hit.worldPos.z), NX_IMPULSE);
					//	actor.addForceAtLocalPos(hit.dir*coeff, NxVec3(hit.worldPos.x,hit.worldPos.y,hit.worldPos.z), NX_IMPULSE);
						//actor.addForceAtLocalPos(hit.dir*coeff, NxVec3(hit.worldPos.x,hit.worldPos.y,hit.worldPos.z), NX_IMPULSE);
												//actor.addForceAtPos(hit.dir*coeff, hit.controller->getPosition(), NX_IMPULSE);
												//actor.addForceAtPos(hit.dir*coeff, hit.worldPos, NX_IMPULSE);
						return NX_ACTION_PUSH ;
					}
				}
			}else //if(group==GROUP_COLLIDABLE_NON_PUSHABLE){
			return NX_ACTION_NONE;
			//}
		}
		

		return NX_ACTION_NONE;
}

